﻿Option Strict On

Imports System.Threading
Imports System.ServiceProcess
Imports System.IO
Imports System.ComponentModel
Imports System.Configuration

Imports Sunts.HyperV.VSS
Imports Sunts.HyperV.Common


Public Class BackupWorker
    Private Backup As Backup

    Public Sub Run()
        Try
            Backup = New Backup(HyperVBackupScheduler.ConnectionString)
            Backup.BackupSchedule = BackupSchedule.Create(HyperVBackupScheduler.ConnectionString)

            'Ensure a backup job has been found that has an active schedule
            If Backup.BackupSchedule Is Nothing Then
                Exit Try
            End If

            Backup.BackupSchedule.BackupJobSchedule.ActualStart = DateTime.Now
            Backup.BackupSchedule.BackupJobSchedule.Update(HyperVBackupScheduler.ConnectionString)
            Backup.LogName = Backup.BackupSchedule.VirtualMachine.VirtualMachineName & " - " & Format(Backup.BackupSchedule.BackupJobSchedule.ActualStart, "yyyy-MM-dd_HH-mm-ss") & ".log"
            Backup.RaiseBackupEvent(BackupEvent.SettingBackupDevice)
            Backup.RaiseBackupEvent(BackupEvent.StartingBackupRoutine)
            Backup.BackupSchedule.BackupJobSchedule = Backup.BackupSchedule.BackupJobSchedule
            Backup.BackupSchedule.VirtualMachine = Backup.BackupSchedule.VirtualMachine
            Backup.BackupSchedule.BackupFolder = Path.Combine(Backup.BackupSchedule.BackupDevice.DevicePath, Backup.BackupSchedule.VirtualMachine.VirtualMachineName, Format(Backup.BackupSchedule.BackupJobSchedule.ActualStart, "yyyy-MM-dd_HH-mm-ss"))

            'Check to see if the job is within it's 180 minute timeout
            'TODO add timeout as a variable 
            If Now() > DateAdd(DateInterval.Minute, 1600000, Backup.BackupSchedule.BackupJobSchedule.ScheduleDateTime) Then
                Backup.RaiseBackupEvent(BackupEvent.BackupExpired)
                Exit Try
            End If

            'Check to see if the backup device is writeable
            If Backup.BackupSchedule.BackupDevice.IsWritable = False Then
                Backup.RaiseBackupEvent(BackupEvent.DeviceOffline)
                Exit Try
            End If

            'job looks good to go so create backup directory
            'TODO add some sort of backup retention code to auto delete old backups
            Directory.CreateDirectory(Backup.BackupSchedule.BackupFolder)

            'initialise vss for shadow copy
            Backup.ProcessBackup()

        Catch ex As Exception
            System.Threading.Thread.Sleep(1000)
            Throw ex
        Finally
            Call JobCompleted()
            Call ScheduleNewJob()
            Backup.Dispose()
        End Try



    End Sub



    Private Sub JobCompleted()
        If Backup.BackupSchedule IsNot Nothing Then
            Try
                Backup.RaiseBackupEvent(BackupEvent.Complete)

                Select Case Backup.BackupProgressEventArgs.BackupCompletionStatus
                    Case BackupCompletionStatus.Success
                        Backup.BackupSchedule.BackupJobSchedule.CompletionStatus = "Success"
                    Case BackupCompletionStatus.DeviceError
                        Backup.BackupSchedule.BackupJobSchedule.CompletionStatus = "Device error: see job log"
                    Case BackupCompletionStatus.CopyError
                        Backup.BackupSchedule.BackupJobSchedule.CompletionStatus = "Copy error: see job log"
                    Case BackupCompletionStatus.VSSError
                        Backup.BackupSchedule.BackupJobSchedule.CompletionStatus = "VSS error: see job log"
                    Case BackupCompletionStatus.Timeout
                        Backup.BackupSchedule.BackupJobSchedule.CompletionStatus = "The job timed out: see job log"
                    Case BackupCompletionStatus.Cancelled
                        Backup.BackupSchedule.BackupJobSchedule.CompletionStatus = "The job was cancelled"
                    Case BackupCompletionStatus.Unknown
                        Backup.BackupSchedule.BackupJobSchedule.CompletionStatus = "An unknown error occured: see job log"
                End Select

                Backup.BackupSchedule.BackupJobSchedule.Progress = "Backup Complete"
                Backup.BackupSchedule.BackupJobSchedule.ActualEnd = DateTime.Now
                Backup.BackupSchedule.BackupJobSchedule.Update(HyperVBackupScheduler.ConnectionString)

                Try
                    Call SubmitMail(Backup.BackupSchedule, Backup.LogName)
                Catch ex As Exception
                    Backup.BackupProgressEventArgs.Exception = ex
                    Backup.RaiseBackupEvent(BackupEvent.ErrorSendingMail)
                End Try

            Catch ex As Exception
                Backup.BackupProgressEventArgs.Exception = ex
                Backup.RaiseBackupEvent(BackupEvent.Exception)
                Throw ex
            End Try
        End If
    End Sub

    Public Sub CancelJob()
        If Backup.BackupSchedule IsNot Nothing Then
            Backup.CancelBackup()
            Backup.BackupSchedule.BackupJobSchedule.Progress = "Cancelling backup..."
            Backup.BackupSchedule.BackupJobSchedule.Update(HyperVBackupScheduler.ConnectionString)
        End If
    End Sub

    Public Sub ScheduleNewJob()
        If Backup.BackupSchedule IsNot Nothing Then
            Backup.BackupSchedule.BackupJobSchedule.ActualStart = Nothing
            Backup.BackupSchedule.BackupJobSchedule.ActualEnd = Nothing
            Backup.BackupSchedule.BackupJobSchedule.Progress = String.Empty

            Select Case Backup.BackupSchedule.BackupJob.BackupRecurrenceType
                Case BackupRecurrenceType.BackupRecurrence.SingleBackup
                    Exit Sub
                Case BackupRecurrenceType.BackupRecurrence.DailyBackup
                    Backup.BackupSchedule.BackupJobSchedule.ScheduleDateTime = Backup.BackupSchedule.BackupJobSchedule.ScheduleDateTime.AddDays(1)
                Case BackupRecurrenceType.BackupRecurrence.WeeklyBackup
                    Backup.BackupSchedule.BackupJobSchedule.ScheduleDateTime = Backup.BackupSchedule.BackupJobSchedule.ScheduleDateTime.AddDays(7)
            End Select
            Backup.RaiseBackupEvent(BackupEvent.JobReschedule)
            Backup.BackupSchedule.BackupJobSchedule.Insert(HyperVBackupScheduler.ConnectionString)
        End If
    End Sub

    Function SubmitMail(ByVal BackupSchedule As BackupSchedule, ByVal Log As String) As Boolean
        Dim MailServer As MailServer
        Dim MailServerCollection As MailServerCollection
        Dim Message As String

        Dim HeaderRow As String
        Dim JobLog As String
        Dim FooterRow As String

        Try
            MailServerCollection = MailServer.SelectAll(HyperVBackupScheduler.ConnectionString)

            If MailServerCollection.Count > 0 Then
                HeaderRow = CreateHeaderRow(BackupSchedule.VirtualMachine.VirtualMachineName)
                JobLog = CreateJobLog(Log)
                FooterRow = CreateFooterRow()

                MailServer = MailServer.SelectAll(HyperVBackupScheduler.ConnectionString).Item(0)
                Message = String.Concat(HeaderRow, JobLog, FooterRow)

                For Each MailRecipient As MailRecipient In MailRecipient.SelectByBackupJobID(BackupSchedule.BackupJob.BackupJobID, HyperVBackupScheduler.ConnectionString)
                    MailFunctions.SendMail(MailServer, MailRecipient, Message)
                Next

                Return True
            End If

        Catch ex As Exception
            Throw ex
        Finally
            MailServerCollection = Nothing
            MailServer = Nothing
            Message = Nothing
            HeaderRow = Nothing
            JobLog = Nothing
            FooterRow = Nothing
        End Try
    End Function




End Class